package dao

import (
	"context"
	"database/sql"
	"errors"
	"github.com/go-sql-driver/mysql"
	"gorm.io/gorm"
	"time"
)

var (
	ErrUserDuplicateEmailOrPhone = errors.New("邮箱/手机号冲突")
	ErrUserNotFound              = gorm.ErrRecordNotFound
)

/*
*
最底层Dao
*/
type UserDao interface {
	Insert(ctx context.Context, u User) error
	FindById(ctx context.Context, uid int64) (User, error)
	FindByEmail(ctx context.Context, email string) (User, error)
	FindByPhone(ctx context.Context, phone string) (User, error)
	FindByWechat(ctx context.Context, openId string) (User, error)
	FindByGithub(ctx context.Context, openId int64) (User, error)
}
type GormUserDAO struct {
	db *gorm.DB
}

func NewGormUserDAO(db *gorm.DB) UserDao {
	return &GormUserDAO{db: db}
}
func (dao *GormUserDAO) Insert(ctx context.Context, u User) error {
	now := time.Now().UnixMilli()
	u.Ctime = now
	u.Utime = now
	err := dao.db.WithContext(ctx).Create(&u).Error
	if mysqlErr, ok := err.(*mysql.MySQLError); ok {
		const duplicateErr uint16 = 1062
		if mysqlErr.Number == duplicateErr {
			return ErrUserDuplicateEmailOrPhone
		}
	}
	return err
}
func (dao *GormUserDAO) FindById(ctx context.Context, uid int64) (User, error) {
	var res User
	err := dao.db.WithContext(ctx).Where("id = ?", uid).First(&res).Error
	return res, err
}
func (dao *GormUserDAO) FindByEmail(ctx context.Context, email string) (User, error) {
	var u User
	err := dao.db.WithContext(ctx).Where("email=?", email).First(&u).Error
	return u, err
}
func (dao *GormUserDAO) FindByPhone(ctx context.Context, phone string) (User, error) {
	var res User
	err := dao.db.WithContext(ctx).Where("phone = ?", phone).First(&res).Error
	return res, err
}
func (dao *GormUserDAO) FindByWechat(ctx context.Context, openId string) (User, error) {
	var res User
	err := dao.db.WithContext(ctx).Where("open_id = ?", openId).First(&res).Error
	return res, err
}
func (dao *GormUserDAO) FindByGithub(ctx context.Context, openId int64) (User, error) {
	var res User
	err := dao.db.WithContext(ctx).Where("github_id = ?", openId).First(&res).Error
	return res, err
}

type User struct {
	Id       int64          `gorm:"primaryKey,autoIncrement"`
	Email    sql.NullString `gorm:"unique"`
	Phone    sql.NullString `gorm:"column:phone"`
	Password string

	WechatUnionID sql.NullString `gorm:"column:union_id"`
	WechatOpenID  sql.NullString `gorm:"column:open_id;unique"`
	GithubId      sql.NullInt64  `gorm:"column:github_id;unique"`
	NodeId        sql.NullString `gorm:"column:node_id"`

	NickName string `gorm:"column:nick_name"`

	Ctime int64
	Utime int64
}

func (User) TableName() string {
	return "user"
}
